package cn.dansj.common.utils.spring.context;

import cn.dansj.common.utils.lang.NotNull;
import cn.dansj.common.utils.transfer.Transformation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.context.ApplicationContext;

import java.util.Arrays;

public abstract class ApplicationContextProvider {
    private static ApplicationContext applicationContext;
    private static final Logger logger = LoggerFactory.getLogger(ApplicationContextProvider.class);

    static void injectApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
        if (applicationContext != ApplicationContextProvider.applicationContext) {
            logger.info("inject applicationContext");
            ApplicationContextProvider.applicationContext = applicationContext;
        }
    }

    // 获取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public static Object getBean(String name) {
        return applicationContext.getBean(name);
    }

    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }

    public static <T> T getBean(String name, Class<T> clazz) {
        return applicationContext.getBean(name, clazz);
    }

    public static boolean hasBean(String name) {
        return Transformation.lambdaTryCatch(() -> applicationContext.containsBean(name), () -> false);
    }

    public static boolean hasBean(Class<?> clazz) {
        return Transformation.lambdaTryCatch(() -> applicationContext.getBeanNamesForType(clazz).length > 0, () -> false);
    }

    public static boolean hasBean(String name, Class<?> clazz) {
        return Transformation.lambdaTryCatch(() -> applicationContext.containsBean(name) && applicationContext.isTypeMatch(name, clazz), () -> false);
    }

    public static boolean hasBean(String... names) {
        return Arrays.stream(names).allMatch(ApplicationContextProvider::hasBean);
    }

    public static boolean hasBean(Class<?>... clazz) {
        return Arrays.stream(clazz).allMatch(ApplicationContextProvider::hasBean);
    }

    public static boolean hasAnyBean(String... names) {
        return Arrays.stream(names).anyMatch(ApplicationContextProvider::hasBean);
    }

    public static boolean hasAnyBean(Class<?>... clazz) {
        return Arrays.stream(clazz).anyMatch(ApplicationContextProvider::hasBean);
    }

    public static boolean hasBean(ListableBeanFactory listableBeanFactory, String... names) {
        return Arrays.stream(names).allMatch(e -> Transformation.lambdaTryCatch(() -> listableBeanFactory.containsBean(e), () -> false));
    }

    public static boolean hasBean(ListableBeanFactory listableBeanFactory, Class<?>... clazz) {
        return Arrays.stream(clazz).allMatch(e -> Transformation.lambdaTryCatch(() -> listableBeanFactory.getBeanNamesForType(e).length > 0, () -> false));
    }

    public static boolean hasAnyBean(ListableBeanFactory listableBeanFactory, String... names) {
        return Arrays.stream(names).anyMatch(e -> Transformation.lambdaTryCatch(() -> listableBeanFactory.containsBean(e), () -> false));
    }

    public static boolean hasAnyBean(ListableBeanFactory listableBeanFactory, Class<?>... clazz) {
        return Arrays.stream(clazz).anyMatch(e -> Transformation.lambdaTryCatch(() -> listableBeanFactory.getBeanNamesForType(e).length > 0, () -> false));
    }

    public static boolean hasBean(ListableBeanFactory listableBeanFactory, String name) {
        return Transformation.lambdaTryCatch(() -> listableBeanFactory.containsBean(name), () -> false);
    }

    public static boolean hasBean(ListableBeanFactory listableBeanFactory, Class<?> clazz) {
        return Transformation.lambdaTryCatch(() -> listableBeanFactory.getBeanNamesForType(clazz).length > 0, () -> false);
    }

    public static boolean hasBean(ListableBeanFactory listableBeanFactory, String name, Class<?> clazz) {
        return Transformation.lambdaTryCatch(() -> listableBeanFactory.containsBean(name) && listableBeanFactory.isTypeMatch(name, clazz), () -> false);
    }
}